package uk.co.q3c.deplan.server.unit.dao.persist;

import java.io.File;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.testng.Assert;
import org.testng.annotations.Test;

import uk.co.q3c.deplan.client.domain.AbstractDomainObject;
import uk.co.q3c.deplan.client.domain.DomainObject;
import uk.co.q3c.deplan.client.domain.dag.ChangeInvalidException;
import uk.co.q3c.deplan.client.domain.dag.CycleDetectedException;
import uk.co.q3c.deplan.client.domain.resource.BaseCalendar;
import uk.co.q3c.deplan.client.domain.resource.CalendarAdjustment;
import uk.co.q3c.deplan.client.domain.resource.IndividualResource;
import uk.co.q3c.deplan.client.domain.resource.PersistenceReferenceException;
import uk.co.q3c.deplan.client.domain.resource.ResourceCalendar;
import uk.co.q3c.deplan.client.domain.resource.ResourceGroup;
import uk.co.q3c.deplan.client.domain.resource.ResourcePool;
import uk.co.q3c.deplan.client.domain.resource.ResourceProfileEntry;
import uk.co.q3c.deplan.client.domain.task.BaseTask;
import uk.co.q3c.deplan.client.domain.task.PlanProfileEntry;
import uk.co.q3c.deplan.client.domain.util.CalendarAdjustments;
import uk.co.q3c.deplan.client.domain.util.DateProfileEntryBase;
import uk.co.q3c.deplan.client.service.PlanManager;
import uk.co.q3c.deplan.client.service.TaskService;
import uk.co.q3c.deplan.google.TreeSet_Test;
import uk.co.q3c.deplan.server.domain.test.TestDomainObject;
import uk.co.q3c.deplan.server.domain.util.Q3CalendarUtil;
import uk.co.q3c.deplan.server.unit.dao.LocalDatastoreTestCase;
import uk.co.q3c.deplan.server.util.ReflectionFieldBuilder;
import util.TestDomainObjectForTree;

import com.googlecode.objectify.Key;

/**
 * Copy the template method for each domain class. {@link #listSetters(AbstractDomainObject)} and
 * {@link #listGetterChecks(AbstractDomainObject)} output skeleton calls to the console.
 * 
 * @author David Sowerby 23 Feb 2010
 * 
 */
@Test
public class PersistAll_UT extends LocalDatastoreTestCase {
	List<Class<? extends AbstractDomainObject>> domainClassList;
	transient protected Logger logger = Logger.getLogger(getClass().getName());

	ReflectionFieldBuilder rfb;
	Map<Class<?>, Object> testValues;
	List<String> fieldsSet;
	List<String> fieldsNotSet;
	int abstractCount;
	Calendar cal = new GregorianCalendar();
	String calDateKey = "20090904";// remember cal offsets monts (starts at 0)
	String dateKey;
	TaskService taskDao;

	@Override
	protected void beforeClass() throws Exception {
		super.beforeClass();
		dateKey = Q3CalendarUtil.dateToKey(cal);
		domainClassList = new ArrayList<Class<? extends AbstractDomainObject>>();
		cal.set(2009, 10, 4, 0, 0, 0);
		rfb = new ReflectionFieldBuilder();
		rfb.setExcludeStatic(false);
		rfb.setExcludeTransient(false);
		testValues = new TreeMap<Class<?>, Object>();
		fieldsSet = new ArrayList<String>();
		fieldsNotSet = new ArrayList<String>();
		// builds list of domain classes into domainClassList, so we can check
		// they have all been done
		buildClasses();
		domainClassList.remove(TestDomainObjectForTree.class);
		logger.info(">>>>>>>>>>>>>>>>>>> There are " + domainClassList.size() + " classes to check, " + Integer.toString(abstractCount)
				+ " abstract classes ignored");
	}

	@Override
	protected void beforeMethod() throws Exception {
		super.beforeMethod();
		connection.closeSession();
		taskDao = connection.taskService();
	}

	/**
	 * Builds a list of classes to test (and store in {@link #domainClassList}, ignoring abstract classes
	 * 
	 * @throws ClassNotFoundException
	 */
	@SuppressWarnings("unchecked")
	private void buildClasses() throws ClassNotFoundException {
		String filePath = "/home/dave/develop/workspace/DePlanGWT/war/WEB-INF/classes/uk/co/q3c/deplan/server/domain";
		List<Class<?>> firstPass = findClasses(new File(filePath), "uk.co.q3c.deplan.server.domain");
		abstractCount = 0;
		for (Class<?> clazz : firstPass) {

			if (AbstractDomainObject.class.isAssignableFrom(clazz)) {
				if (Modifier.isAbstract(clazz.getModifiers())) {
					System.out.println(clazz.getSimpleName() + " is abstract, ignore");
					abstractCount++;
				} else {
					domainClassList.add((Class<? extends AbstractDomainObject>) clazz);
				}
			}
		}
		for (Class<? extends AbstractDomainObject> c2 : domainClassList) {
			System.out.println(c2 + "  " + Integer.toString(c2.getModifiers()));
		}
	}

	/**
	 * Recursive method used to find all classes in a given directory and subdirs.
	 * 
	 * @param directory
	 *            The base directory
	 * @param packageName
	 *            The package name for classes found inside the base directory
	 * @return The classes
	 * @throws ClassNotFoundException
	 */
	private List<Class<?>> findClasses(File directory, String packageName) throws ClassNotFoundException {
		List<Class<?>> classes = new ArrayList<Class<?>>();
		if (!directory.exists()) {
			logger.warn(directory + " does not exist");
			return classes;
		}
		File[] files = directory.listFiles();
		for (File file : files) {
			// System.out.println(file.toString());
			if (file.isDirectory()) {
				assert !file.getName()
						.contains(".");
				classes.addAll(findClasses(file, packageName + "." + file.getName()));
			} else if (file.getName()
					.endsWith(".class")) {
				classes.add(Class.forName(packageName + '.' + file.getName()
						.substring(0, file.getName()
								.length() - 6)));
			}
		}
		return classes;
	}

	@Override
	// @AfterClass
	protected void afterClass() throws Exception {
		if (domainClassList.size() != 0) {
			String s = StringUtils.join(domainClassList, "\n");
			System.out.println(">>>>>>>>>>>>>>>>>>> Missed classes\n" + s);
			throw new Exception(domainClassList.size() + " domain classes missed ");
		}
		super.afterClass();
	}

	public void abstractTask() throws CycleDetectedException, ChangeInvalidException, PersistenceReferenceException {

		IndividualResource r = new IndividualResource(connection);
		r.setName("dsowerby");
		r.save();

		BaseTask succ1 = new BaseTask(connection);
		succ1.save();

		// BaseTask succ2 = new BaseTask(connection);

		BaseTask pred1 = new BaseTask(connection);
		pred1.save();

		BaseTask pred2 = new BaseTask(connection);
		pred2.save();

		BaseTask pst = new BaseTask(connection);
		pst.save();

		BaseTask iut = new BaseTask(connection);
		// listSetters(iut);
		// listGetterChecks(iut);
		iut.setAssignedUnits(1.5);
		iut.setAssignedResource(r);
		iut.setWorkRemaining(100);
		iut.setWorkDone(150, r, cal.getTime());
		// iut.setFixedDuration(true);
		iut.setWorkAllocated(65);

		iut.addToWorkDone(14, r, cal.getTime());
		iut.addToWorkDone(17, r, cal.getTime());
		iut.setActualFinish(cal.getTime());
		iut.setStartRemaining(cal.getTime());
		iut.setPlannedFinish(cal.getTime());
		iut.setActualStart(cal.getTime());
		pred1.save();
		iut.save();
		iut.addPredecessor(pred1);
		iut.addPredecessor(pred2);
		iut.addSuccessor(succ1);
		// iut.addSuccessor(succ1);
		iut.setDuration(5.6);
		// ignored for persistence it is just another way of adding
		// successors/predecessors
		// out.setDependencies();
		iut.setPriority(101);
		iut.setParentTask(pst);
		iut.setTargetStartDate(new Date());
		iut.setTargetFinishDate(new Date());
		iut.setSpecification("specification");
		// transient
		// out.setTempId(23);
		iut.setName("Woger");
		iut.setDiscarded(true);
		iut.setDiscardedDate(new Date());
		iut.setValid(true);

		iut.save();
		connection.closeSession();
		BaseTask riut = connection.taskService()
				.getObjectFromKey(connection.taskService()
						.keyFor(iut));
		Assert.assertNotSame(iut, riut);
		Assert.assertEquals(iut.getClass(), riut.getClass());
		Assert.assertEquals(keyFor(iut.getAssignedResource()), keyFor(riut.getAssignedResource()));
		Assert.assertEquals(iut.getAssignedUnits(), riut.getAssignedUnits());
		Assert.assertEquals(iut.getWorkDone(), riut.getWorkDone());
		Assert.assertEquals(iut.getWorkRemaining(), riut.getWorkRemaining());
		Assert.assertEquals(iut.getTotalWork(), riut.getTotalWork());
		// removed - because profiles will be different instances the way this
		// test is set up
		// provided work done is correct these tests not needed
		// Assert.assertEquals(iut.getProfile(r),
		// riut.getProfile((IndividualResource) riut.getAssignedResource()));
		// Assert.assertEquals(iut.getProfiles(), riut.getProfiles());
		Assert.assertEquals(iut.getWorkDone(), riut.getWorkDone());
		Assert.assertEquals(iut.getWorkAllocated(), riut.getWorkAllocated());

		Assert.assertEquals(iut.getWorkPlanned(r, new Date()), riut.getWorkPlanned(r, new Date()));
		Assert.assertEquals(iut.getPlannedFinish(), riut.getPlannedFinish());
		Assert.assertEquals(iut.getActualStart(), riut.getActualStart());
		Assert.assertEquals(iut.getActualFinish(), riut.getActualFinish());
		Assert.assertEquals(iut.getPredecessors(), riut.getPredecessors());
		Assert.assertEquals(iut.getSuccessors(), riut.getSuccessors());
		Assert.assertEquals(iut.getStart(), riut.getStart());
		Assert.assertEquals(iut.getDuration(), riut.getDuration());
		Assert.assertEquals(iut.getStartRemaining(), riut.getStartRemaining());
		Assert.assertEquals(iut.getPriority(), riut.getPriority());
		Assert.assertEquals(iut.getTaskId(), riut.getTaskId());
		Assert.assertEquals(iut.getTargetStartDate(), riut.getTargetStartDate());
		Assert.assertEquals(iut.getTargetFinishDate(), riut.getTargetFinishDate());
		Assert.assertEquals(iut.getParentTask(), riut.getParentTask());
		Assert.assertEquals(iut.getSpecification(), riut.getSpecification());
		Assert.assertEquals(iut.getTempId(), riut.getTempId());
		Assert.assertEquals(iut.getName(), riut.getName());
		Assert.assertEquals(keyFor(iut), keyFor(riut));

		Assert.assertEquals(iut.getDiscarded(), riut.getDiscarded());
		Assert.assertEquals(iut.getDiscardedDate(), riut.getDiscardedDate());
		Assert.assertEquals(iut.getConnection(), riut.getConnection());
		Assert.assertEquals(iut.getClass(), riut.getClass());
		connection.closeSession();

		domainClassList.remove(BaseTask.class);
	}

	/**
	 * This is just here to remove classes which don't need testing but are descendants of {@link AbstractDomainObject}
	 */
	public void remove() {
		domainClassList.remove(TestDomainObject.class);
		// domainClassList.remove(ResourceDailyProfile_TreeSet.class);

	}

	public void individualResource() throws CycleDetectedException, ChangeInvalidException, PersistenceReferenceException {
		connection.openSession();
		IndividualResource iut = new IndividualResource(connection);
		Calendar bookingDate = new GregorianCalendar();
		Calendar adjustmentDate = new GregorianCalendar();

		BaseTask pt = new BaseTask(connection);

		// listSetters(iut);
		// listGetterChecks(iut);

		iut.addAdjustment(adjustmentDate.getTime(), true, 48);
		iut.setBaseCalendar(new BaseCalendar(connection));
		iut.setName("dsowerby");
		iut.setConnection(connection);
		iut.setDiscarded(false);
		iut.bookEffort(133, bookingDate.getTime(), pt);
		// automatic
		// iut.setDiscardedDate();
		iut.setValid(true);
		iut.save();
		connection.closeSession();

		connection.openSession();
		IndividualResource riut = testdao.getObjectFromKey(keyFor(iut));
		// connection.closeSession();
		Assert.assertNotSame(iut, riut);
		// connection.openSession();

		Assert.assertEquals(iut.getResources()
				.toString(), riut.getResources()
				.toString());
		ArrayList<IndividualResource> list = new ArrayList<IndividualResource>();
		ArrayList<IndividualResource> list1 = new ArrayList<IndividualResource>();
		Assert.assertEquals(iut.getIndividualResources(list)
				.toString(), riut.getIndividualResources(list1)
				.toString());
		// won't match at reference level, but tested by checking working time
		// Assert.assertEquals(iut.getBaseCalendar(), riut.getBaseCalendar());
		// Assert.assertEquals(iut.getResourceCalendar(),
		// riut.getResourceCalendar());
		int x = iut.getWorkingTime(adjustmentDate.getTime());
		int y = riut.getWorkingTime(adjustmentDate.getTime());
		Assert.assertEquals(x, y);
		Assert.assertEquals(iut.getWorkingTime(adjustmentDate.getTime()), riut.getWorkingTime(adjustmentDate.getTime()));
		Assert.assertEquals(iut.getTotalEffortBooked(), riut.getTotalEffortBooked());
		Assert.assertEquals(iut.getName(), riut.getName());
		Assert.assertEquals(keyFor(iut), keyFor(riut));
		Assert.assertEquals(keyFor(iut), keyFor(riut));
		Assert.assertEquals(iut.getClass(), riut.getClass());

		Assert.assertEquals(iut.getDiscarded(), riut.getDiscarded());
		Assert.assertEquals(iut.getDiscardedDate(), riut.getDiscardedDate());
		Assert.assertEquals(iut.getConnection(), riut.getConnection());
		Assert.assertEquals(iut.getClass(), riut.getClass());

		connection.closeSession();
		domainClassList.remove(IndividualResource.class);
		logger.info(" remaining classes " + domainClassList.toString());
	}

	/**
	 * Just to shorten a lot of repeated lines
	 * 
	 * @param <T>
	 * @param dob
	 * @return
	 */
	private <T extends DomainObject> Key<T> keyFor(T dob) {
		return testdao.keyFor(dob);
	}

	public void resourceGroup() throws CycleDetectedException, ChangeInvalidException, PersistenceReferenceException {
		ResourceGroup iut = new ResourceGroup(connection); // change class as
		// needed
		iut.setConnection(connection);
		Calendar bookingDate = new GregorianCalendar();
		Calendar adjustmentDate = new GregorianCalendar();
		BaseTask pt = new BaseTask(connection);
		pt.setConnection(connection);

		IndividualResource ir1 = new IndividualResource(connection);
		ir1.setConnection(connection);
		ir1.setName("ir1");
		ir1.save();

		IndividualResource ir2 = new IndividualResource(connection);
		ir2.setConnection(connection);
		ir2.setName("ir2");
		ir2.save();

		IndividualResource ir3 = new IndividualResource(connection);
		ir3.setConnection(connection);
		ir3.setName("ir3");
		ir3.save();

		// listSetters(iut);
		// listGetterChecks(iut);
		connection.openSession();

		List<IndividualResource> resources = new ArrayList<IndividualResource>();
		resources.add(ir1);
		resources.add(ir2);

		//
		// set up the item under test, before it is saved
		//
		iut.addAdjustment(adjustmentDate.getTime(), true, 48);
		iut.setResources(resources);
		// duplicate as far as persistence concerned
		// iut.setResources();
		iut.addResource(ir3);
		iut.setProportionalBooking(true);
		iut.setName("groupie");
		iut.setConnection(connection);
		iut.setDiscarded(false);
		iut.setDiscardedDate(new Date());
		iut.setValid(false);

		iut.bookEffort(133, bookingDate.getTime(), pt);
		iut.save();
		connection.closeSession();

		// get a copy of the object from persistence - change CLASS!
		connection.openSession();
		ResourceGroup riut = testdao.getObjectFromKey(keyFor(iut));
		connection.closeSession();
		Assert.assertNotSame(iut, riut); // make sure they are not the same
		// instance, that would be cheating!

		// some objects will call persistence for some of their fields
		connection.openSession();
		//
		// do the Assert stuff here
		//

		String iutName = iut.getResource("ir3")
				.getName();
		String riutName = riut.getResource("ir3")
				.getName();
		Assert.assertEquals(iutName, riutName);

		iutName = iut.getResource("ir2")
				.getName();
		riutName = riut.getResource("ir2")
				.getName();
		Assert.assertEquals(iutName, riutName);

		iutName = iut.getResource("ir1")
				.getName();
		riutName = riut.getResource("ir1")
				.getName();
		Assert.assertEquals(iutName, riutName);

		Assert.assertEquals(iut.count(), riut.count());

		// these don't come out in the same order but previous Asserts check
		// they are all there
		// Assert.assertEquals(iut.getResources().toString(),
		// riut.getResources().toString());
		// ArrayList<IndividualResource> list = new
		// ArrayList<IndividualResource>();
		// ArrayList<IndividualResource> list1 = new
		// ArrayList<IndividualResource>();
		// Assert.assertEquals(iut.getIndividualResources(list).toString(),
		// riut.getIndividualResources(list1).toString());
		Assert.assertEquals(iut.getName(), riut.getName());
		Assert.assertEquals(keyFor(iut), keyFor(riut));
		Assert.assertEquals(iut.getClass(), riut.getClass());

		Assert.assertEquals(iut.getDiscarded(), riut.getDiscarded());
		Assert.assertEquals(iut.getDiscardedDate(), riut.getDiscardedDate());
		Assert.assertEquals(iut.getConnection(), riut.getConnection());
		Assert.assertEquals(iut.getClass(), riut.getClass());

		connection.closeSession();
		domainClassList.remove(ResourceGroup.class); // change CLASS!
	}

	/**
	 * there is nothing to do on this it is tested by {@link ResourceProfileEntry} and {@link PlanProfileEntry}
	 */
	public void dateProfileEntryBase() {
		domainClassList.remove(DateProfileEntryBase.class); // change CLASS!

	}

	/**
	 * This fails. When iut is saved, TresSet loses its root value, so when a call to getEntry is made it throws an error yet the contained
	 * entry is fine. See also {@link TreeSet_Test}. Further investigation - TresSet root is transient, so that is probably why this
	 * happens,but don't know how to fix it other than using a LinkedList instead.
	 */
	// @Test(enabled = false)
	// public void resourceDailyProfile_treeSet() {
	// ResourceDailyProfile_TreeSet iut = new
	// ResourceDailyProfile_TreeSet(connection); // change class as needed
	// cal.setTime(Q3DateUtil.keyToDate(calDateKey));
	// listSetters(iut);
	// listGetterChecks(iut);
	// connection.openSession();
	// //
	// // set up the item under test, before it is saved
	// //
	// ResourceProfileEntry rpe = new ResourceProfileEntry(testdao, calDateKey);
	// rpe.allocateWork(202);
	// iut.addEntry(rpe);
	// iut.setName("superfluous");
	// iut.setDiscarded(true);
	// iut.setDiscardedDate(new Date());
	// iut.setValid(false);
	// iut.save();
	// connection.closeSession();
	//
	// // get a copy of the object from persistence - change CLASS!
	// connection.openSession();
	// ResourceDailyProfile_TreeSet riut = (ResourceDailyProfile_TreeSet)
	// testdao.getObjectFromKey(ResourceDailyProfile_TreeSet.class,
	// keyFor(iut));
	// connection.closeSession();
	// Assert.assertNotSame(iut, riut); // make sure they are not the same
	// instance, that would be cheating!
	//
	// // some objects will call persistence for some of their fields
	// connection.openSession();
	// //
	// // do the Assert stuff here
	// //
	// System.out.println(rpe);
	// Assert.assertEquals(iut.size(), riut.size());
	// ResourceProfileEntry rpex = riut.getEntry(calDateKey);
	// Assert.assertEquals(iut.getEntry(cal.getTime()), rpex);
	// Assert.assertEquals((iut.getEntry(cal.getTime())).getUtilisedTime(),
	// rpex.getUtilisedTime());
	// Assert.assertEquals(iut.getEntry(cal.getTime()),
	// riut.getEntry(cal.getTime()));
	// Assert.assertEquals(iut.getEntry(cal.getTime()),
	// riut.getEntry(cal.getTime()));
	// Assert.assertEquals(iut.getName(), riut.getName());
	// Assert.assertEquals(keyFor(iut), keyFor(riut));
	// 
	// 
	// Assert.assertEquals(iut.getDiscarded(), riut.getDiscarded());
	// Assert.assertEquals(iut.getDiscardedDate(), riut.getDiscardedDate());
	// Assert.assertEquals(iut.getConnection(), riut.getConnection());
	// Assert.assertEquals(iut.getClass(), riut.getClass());
	// connection.closeSession();
	// domainClassList.remove(ResourceDailyProfile_TreeSet.class); // change
	// CLASS!
	// }

	public void resourcePool() throws CycleDetectedException, ChangeInvalidException, PersistenceReferenceException {
		ResourcePool iut = new ResourcePool(connection); // change class as
		// needed
		ResourceGroup group1 = new ResourceGroup(connection);
		group1.setName("group1");
		ResourceGroup group2 = new ResourceGroup(connection);
		group2.setName("group2");
		IndividualResource ir1 = new IndividualResource(connection);
		ir1.setName("dsowerby");
		ir1.save();
		IndividualResource ir2 = new IndividualResource(connection);
		ir2.setName("mpaine");
		ir2.save();
		group1.addResource(ir1);
		group1.addResource(ir2);
		group2.addResource(ir1);
		group1.save();
		group2.save();
		IndividualResource irs[] = { ir1, ir2 };

		// do the test

		connection.openSession();
		//
		// set up the item under test, before it is saved
		//
		// iut.setBaseCalendar(); //this should not be used directly, base
		// calendar taken from persistence
		iut.setConnection(connection);
		iut.addResource(group1);
		iut.addResource(group2);
		iut.addResources(irs);
		iut.setDefaultResourceName("group1");
		iut.setName("pool");
		iut.setDiscarded(false);
		iut.setDiscardedDate(null);
		iut.setValid(true);
		iut.save();
		connection.closeSession();

		// get a copy of the object from persistence - change CLASS!
		connection.openSession();
		ResourcePool riut = testdao.getObjectFromKey(keyFor(iut));
		connection.closeSession();
		Assert.assertNotSame(iut, riut); // make sure they are not the same
		// instance, that would be cheating!

		// some objects will call persistence for some of their fields
		connection.openSession();
		//
		// do the Assert stuff here
		//
		Assert.assertEquals(ir1.getName(), riut.getResource("dsowerby")
				.getName());
		Assert.assertEquals(iut.getGroups()
				.size(), riut.getGroups()
				.size());
		ResourceGroup g1a = (ResourceGroup) iut.getResource("group1");
		ResourceGroup g1b = (ResourceGroup) riut.getResource("group1");
		Assert.assertEquals(g1a.size(), g1b.size());
		Assert.assertTrue(g1a.containsAll(new String[] { "dsowerby", "mpaine" }));
		Assert.assertTrue(g1b.containsAll(new String[] { "dsowerby", "mpaine" }));
		Assert.assertEquals(iut.getResource("mpaine")
				.getName(), riut.getResource("mpaine")
				.getName());
		Assert.assertEquals(iut.getIndividuals()
				.size(), riut.getIndividuals()
				.size());
		Assert.assertEquals(iut.getDefaultResourceName(), riut.getDefaultResourceName());
		Assert.assertEquals(iut.getName(), riut.getName());
		Assert.assertEquals(keyFor(iut), keyFor(riut));

		Assert.assertEquals(iut.getDiscarded(), riut.getDiscarded());
		Assert.assertEquals(iut.getDiscardedDate(), riut.getDiscardedDate());
		Assert.assertEquals(iut.getConnection(), riut.getConnection());
		Assert.assertEquals(iut.getClass(), riut.getClass());
		Assert.assertNotNull(((IndividualResource) riut.getResource("mpaine")).getBaseCalendar());
		connection.closeSession();
		domainClassList.remove(ResourcePool.class); // change CLASS!
	}

	public void baseCalendar() throws CycleDetectedException, ChangeInvalidException, PersistenceReferenceException {
		BaseCalendar iut = new BaseCalendar(connection); // change class as
		// needed
		Calendar cal = new GregorianCalendar();
		cal.set(2009, 9, 9, 11, 11);
		listSetters(iut);
		listGetterChecks(iut);
		connection.openSession();
		//
		// set up the item under test, before it is saved
		//
		iut.addAdjustment(cal.getTime(), false, 5);
		iut.addAdjustment(cal.getTime(), false, 5);
		iut.addAdjustment(2009, 9, 9, false, 5);
		iut.setName("base");
		iut.setDiscarded(false);
		iut.setDiscardedDate(new Date());
		iut.setValid(true);
		// iut.setConnection();
		connection.calendarService()
				.save(iut);
		connection.closeSession();

		// get a copy of the object from persistence - change CLASS!
		connection.openSession();
		BaseCalendar riut = testdao.getObjectFromKey(keyFor(iut));
		connection.closeSession();
		Assert.assertNotSame(iut, riut); // make sure they are not the same
		// instance, that would be cheating!

		// some objects will call persistence for some of their fields
		connection.openSession();
		//
		// do the Assert stuff here
		//
		// only looking to see that there is a default working time set.
		Assert.assertEquals(iut.getBaseWorkingTime()
				.getClass(), riut.getBaseWorkingTime()
				.getClass());
		Assert.assertEquals(iut.getAdjustments()
				.size(), riut.getAdjustments()
				.size());
		Assert.assertEquals(iut.getWorkingTime(cal.getTime()), riut.getWorkingTime(cal.getTime()));
		Assert.assertEquals(iut.getName(), riut.getName());
		Assert.assertEquals(keyFor(iut), keyFor(riut));
		Assert.assertEquals(iut.getDiscarded(), riut.getDiscarded());
		Assert.assertEquals(iut.getDiscardedDate(), riut.getDiscardedDate());
		Assert.assertEquals(iut.getConnection(), riut.getConnection());
		Assert.assertEquals(iut.getClass(), riut.getClass());
		connection.closeSession();
		domainClassList.remove(BaseCalendar.class); // change CLASS!
	}

	public void resourceCalendar() throws CycleDetectedException, ChangeInvalidException, PersistenceReferenceException {
		ResourceCalendar iut = new ResourceCalendar(connection); // change class
		// as needed
		Calendar cal = new GregorianCalendar();
		cal.set(2009, 9, 9, 11, 11);
		listSetters(iut);
		listGetterChecks(iut);
		connection.openSession();
		//
		// set up the item under test, before it is saved
		//
		iut.addAdjustment(cal.getTime(), false, 5);
		iut.addAdjustment(cal.getTime(), false, 5);
		iut.addAdjustment(2009, 9, 9, false, 5);
		iut.setName("resource");
		iut.setDiscarded(false);
		iut.setDiscardedDate(new Date());
		iut.setValid(true);
		// iut.setConnection();
		iut.save();
		connection.closeSession();

		// get a copy of the object from persistence - change CLASS!
		connection.openSession();
		ResourceCalendar riut = testdao.getObjectFromKey(keyFor(iut));
		connection.closeSession();
		Assert.assertNotSame(iut, riut); // make sure they are not the same
		// instance, that would be cheating!

		// some objects will call persistence for some of their fields
		connection.openSession();
		//
		// do the Assert stuff here
		//
		// only looking to see that there is a default working time set.
		Assert.assertEquals(iut.getBaseWorkingTime()
				.getClass(), riut.getBaseWorkingTime()
				.getClass());
		Assert.assertEquals(iut.getAdjustments()
				.size(), riut.getAdjustments()
				.size());
		Assert.assertEquals(iut.getWorkingTime(cal.getTime()), riut.getWorkingTime(cal.getTime()));
		Assert.assertEquals(iut.getName(), riut.getName());
		Assert.assertEquals(keyFor(iut), keyFor(riut));

		Assert.assertEquals(iut.getDiscarded(), riut.getDiscarded());
		Assert.assertEquals(iut.getDiscardedDate(), riut.getDiscardedDate());
		Assert.assertEquals(iut.getConnection(), riut.getConnection());
		Assert.assertEquals(iut.getClass(), riut.getClass());
		connection.closeSession();
		domainClassList.remove(ResourceCalendar.class); // change CLASS!
	}

	public void calendarAdjustments() throws CycleDetectedException, ChangeInvalidException, PersistenceReferenceException {
		CalendarAdjustments iut = new CalendarAdjustments(connection); // change
		// class
		// as
		// needed

		listSetters(iut);
		listGetterChecks(iut);
		connection.openSession();
		//
		// set up the item under test, before it is saved
		//
		CalendarAdjustment cadj = new CalendarAdjustment();
		cadj.setDate(cal.getTime());
		cadj.setAdjustment(23);
		cadj.setAbsolute(true);
		iut.add(cal.getTime(), cadj);
		iut.setName("wasted");
		iut.setDiscarded(true);
		iut.setDiscardedDate(new Date());
		iut.setValid(false);
		iut.setConnection(connection);
		connection.calendarService()
				.save(iut);
		connection.closeSession();

		// get a copy of the object from persistence - change CLASS!
		connection.openSession();
		CalendarAdjustments riut = testdao.getObjectFromKey(keyFor(iut));
		connection.closeSession();
		Assert.assertNotNull(riut);
		Assert.assertNotSame(iut, riut); // make sure they are not the same
		// instance, that would be cheating!

		// some objects will call persistence for some of their fields
		connection.openSession();
		//
		// do the Assert stuff here
		//

		Assert.assertEquals(iut.get(cal.getTime())
				.getAdjustment(), riut.get(cal.getTime())
				.getAdjustment());
		Assert.assertEquals(iut.get(cal.getTime())
				.getDate(), riut.get(cal.getTime())
				.getDate());
		Assert.assertEquals(iut.getName(), riut.getName());
		Assert.assertEquals(keyFor(iut), keyFor(riut));
		Assert.assertEquals(iut.getConnection(), riut.getConnection());

		Assert.assertEquals(iut.getDiscarded(), riut.getDiscarded());
		Assert.assertEquals(iut.getDiscardedDate(), riut.getDiscardedDate());
		Assert.assertEquals(iut.getConnection(), riut.getConnection());
		Assert.assertEquals(iut.getKeyId(), riut.getKeyId());
		Assert.assertEquals(iut.getClass(), riut.getClass());
		connection.closeSession();
		domainClassList.remove(CalendarAdjustments.class); // change CLASS!
	}

	public void planManager() throws CycleDetectedException, ChangeInvalidException, PersistenceReferenceException {
		PlanManager iut = new PlanManager(connection); // change class as needed

		listSetters(iut);
		listGetterChecks(iut);
		connection.openSession();
		//
		// set up the item under test, before it is saved
		//
		iut.getCurrentDate(); // forces date set
		iut.setHorizon(433);
		iut.setName("unused");
		iut.setDiscarded(false);
		iut.setDiscardedDate(null);
		iut.setValid(true);
		iut.setConnection(connection);
		iut.save();
		connection.closeSession();

		// get a copy of the object from persistence - change CLASS!
		connection.openSession();
		PlanManager riut = testdao.getObjectFromKey(keyFor(iut));
		connection.closeSession();
		Assert.assertNotNull(riut);
		Assert.assertNotSame(iut, riut); // make sure they are not the same
		// instance, that would be cheating!

		// some objects will call persistence for some of their fields
		connection.openSession();
		//
		// do the Assert stuff here
		//
		Assert.assertEquals(iut.getHorizon(), riut.getHorizon());
		Assert.assertEquals(iut.getPlanEnd(), riut.getPlanEnd());
		Assert.assertEquals(iut.getCurrentDate(), riut.getCurrentDate());
		Assert.assertEquals(iut.getName(), riut.getName());
		Assert.assertEquals(keyFor(iut), keyFor(riut));
		Assert.assertEquals(iut.getConnection(), riut.getConnection());

		Assert.assertEquals(iut.getDiscarded(), riut.getDiscarded());
		Assert.assertEquals(iut.getDiscardedDate(), riut.getDiscardedDate());
		Assert.assertEquals(iut.getConnection(), riut.getConnection());
		Assert.assertEquals(iut.getKeyId(), riut.getKeyId());
		Assert.assertEquals(iut.getClass(), riut.getClass());
		connection.closeSession();
		domainClassList.remove(PlanManager.class); // change CLASS!
	}

	@Test(enabled = false)
	public void template() {
		IndividualResource iut = new IndividualResource(connection); // change
		// class
		// as
		// needed

		listSetters(iut);
		listGetterChecks(iut);
		connection.openSession();
		//
		// set up the item under test, before it is saved
		//
		iut.save();
		connection.closeSession();

		// get a copy of the object from persistence - change CLASS!
		connection.openSession();
		IndividualResource riut = testdao.getObjectFromKey(keyFor(iut));
		connection.closeSession();
		Assert.assertNotNull(riut);
		Assert.assertNotSame(iut, riut); // make sure they are not the same
		// instance, that would be cheating!

		// some objects will call persistence for some of their fields
		connection.openSession();
		//
		// do the Assert stuff here
		//

		connection.closeSession();
		Assert.fail("incomplete");
		domainClassList.remove(IndividualResource.class); // change CLASS!
	}

	private void listSetters(AbstractDomainObject out) {
		Method[] methods = out.getClass()
				.getMethods();
		List<Method> setters = new ArrayList<Method>();
		for (int i = 0; i < methods.length; i++) {
			Method method = methods[i];
			if (method.getName()
					.startsWith("set")) {
				if (method.getName()
						.contains("Saas")) {
					// ignore
				} else {
					setters.add(method);
				}
			}
			if (method.getName()
					.startsWith("add")) {
				if (!method.getName()
						.contains("Listener")) {
					setters.add(method);
				}
			}

		}
		System.out.println("\n\n" + out.getClass()
				.getSimpleName() + "\n");
		for (Method setter : setters) {
			System.out.println("iut." + setter.getName() + "();");
		}
		System.out.println("\n\n");

	}

	private void listGetterChecks(AbstractDomainObject out) {
		Method[] methods = out.getClass()
				.getMethods();
		List<Method> getters = new ArrayList<Method>();
		for (int i = 0; i < methods.length; i++) {
			Method method = methods[i];
			if (method.getName()
					.startsWith("get")) {
				getters.add(method);
			}
		}

		System.out.println("\n\n" + out.getClass()
				.getSimpleName() + "\n");
		for (Method getter : getters) {
			String getterName = getter.getName() + "()";
			System.out.println("Assert.assertEquals(iut." + getterName + ",riut." + getterName + ");");
		}
		System.out.println("\n\n");

	}
	// protected void testStepsa(Class<? extends AbstractDomainObject> clazz)
	// throws Exception {
	// fieldsSet.clear();
	// fieldsNotSet.clear();
	// AbstractDomainObject testObject = clazz.newInstance();
	// System.out.print("\n----------------------------------------" +
	// clazz.getSimpleName() + "-----------------------------------\n");
	// List<Field> fields = getFieldsToProcess(clazz);
	// // for each field, populate by setter, (or adder for collections) with a
	// test value dependent on type
	// for (Field f : fields) {
	// Object value = testValue(f, fields);
	// if (value != null) {
	// fieldsSet.add(f.getName() + " set with " +
	// value.getClass().getSimpleName());
	// } else {
	// fieldsNotSet.add(f.getName());
	// }
	// }
	// System.out.println("\n\nFields set:");
	// for (String s : fieldsSet) {
	// System.out.println(s);
	// }
	// System.out.println("\n\nFields not set:");
	// for (String s : fieldsNotSet) {
	// System.out.println(s);
	// }
	// specialCaseSetup(testObject);
	// // save the object, and make sure it is detached.
	//
	// // reload the object, make sure it is a different instance (object !=
	// object)
	//
	// // compare each field and make sure it has the same value in each
	// instance
	// // use getters, not direct reading of fields, because of lazy loading of
	// some references
	//
	// }

	// private void specialCaseSetup(AbstractDomainObject testObject) {
	// if (testObject instanceof IndividualResource) {
	// IndividualResource r = (IndividualResource) testObject;
	// Calendar cal = new GregorianCalendar();
	// cal.set(2010, 3, 4, 11, 10, 9);
	// r.addAdjustment(cal, true, 33);
	// cal.set(2010, 3, 5, 11, 10, 9);
	// r.addAdjustment(cal, false, 63);
	// }
	//
	// }

	// /**
	// * Builds a list of fields for which a test value will be needed. Excludes
	// fields prefixed with "jdo" (I presume these are added by
	// the
	// * DataNucleus bytecode enhancer), the primary k"key" field and the
	// serialisation id "serialVersionUID" (because that is always
	// final);
	// * any instances of {@link ReferenceKeyList}
	// *
	// * @param clazz
	// * @return
	// * @throws InstantiationException
	// * @throws IllegalAccessException
	// * @throws ClassNotFoundException
	// */
	// private List<Field> getFieldsToProcess(Class<? extends
	// AbstractDomainObject> clazz) throws InstantiationException,
	// IllegalAccessException,
	// ClassNotFoundException {
	// EnumMap<FieldTypes, List<Field>> fieldMap =
	// rfb.buildFieldList(clazz.newInstance());
	// // merge into one big list
	// List<Field> fieldsRaw = new ArrayList<Field>();
	// for (FieldTypes ft : fieldMap.keySet()) {
	// fieldsRaw.addAll(fieldMap.get(ft));
	// }
	// // strip out unwanted fields
	// List<Field> fields = new ArrayList<Field>();
	// for (Field f : fieldsRaw) {
	// if (Q3StringUtil.startsWithIgnoreCase(f.getName(), "jdo")) {
	// // do nothing, ignore
	// } else {
	// if ((f.getName().equals("serialVersionUID") ||
	// (f.getName().equals("key"))) ||
	// f.getName().equals("structureChangeListeners")) {
	// // do nothing, ignore
	// } else {
	//
	// if ((f.getType() == ReferenceKeyList.class) || (f.getType() ==
	// PropertyChangeSupport.class)
	// || (f.getType() == CalendarAdjustments.class) || (f.getType() ==
	// WorkingTime.class)
	// || (f.getType() == SimpleDateFormat.class) || (f.getType() ==
	// DateProfileCache.class)) {
	//
	// } else {
	// if ((f.getType() == List.class && (getGeneric(f) == Key.class))) {
	//
	// } else {
	// fields.add(f);
	// }
	// }
	// }
	// }
	// }
	// System.out.println(fields.size() + " fields");
	// for (Field f : fields) {
	// System.out.println(f.getName());
	// }
	//
	// return fields;
	// }

	// /**
	// * Scans all classes accessible from the context class loader which belong
	// to the given package and subpackages.
	// *
	// * @param packageName
	// * The base package
	// * @return The classes
	// * @throws ClassNotFoundException
	// * @throws IOException
	// */
	// private static Class<?>[] getClasses(String packageName) throws
	// ClassNotFoundException, IOException {
	// ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
	// assert classLoader != null;
	// String path = packageName.replace('.', '/');
	// Enumeration<URL> resources = classLoader.getResources(path);
	// List<File> dirs = new ArrayList<File>();
	// while (resources.hasMoreElements()) {
	// URL resource = resources.nextElement();
	// dirs.add(new File(resource.getFile()));
	// }
	// ArrayList<Class<?>> classes = new ArrayList<Class<?>>();
	// for (File directory : dirs) {
	// classes.addAll(findClasses(directory, packageName));
	// }
	// return classes.toArray(new Class[classes.size()]);
	// }

	// private Object testValue(Field field, List<Field> fields) throws
	// Exception {
	// // ClassLoader classLoader = new
	// ResourceGroup().getClass().getClassLoader();
	// Class<?> fieldType = field.getType();
	// Class<?> generic = getGeneric(field);
	//
	// if (field.getName().equals("testdao")) {
	// return testdao;
	// }
	//
	// // relies on naming convention to separate the stem of the property name,
	// for example 'resourceKey' becomes 'resource', then returns
	// // a test value for the resource, not the key
	// if (fieldType == Key.class) {
	// String keyName = field.getName();
	// String suff = keyName.substring(keyName.length() - 3, keyName.length());
	// if (suff.endsWith("Key")) {
	// String referenceName = keyName.substring(0, keyName.length() - 3);
	// for (Field f : fields) {
	// if (f.getName().equals(referenceName)) {
	// return testValue(f, fields);
	// }
	// }
	// } else {
	// throw new Exception("Wrong name structure for key " + keyName +
	// " should end in 'Key' not " + suff);
	// }
	// }
	//
	// // collections
	// // create 2 test values of the type specified by the generic. Returned in
	// a List regardless of collection type - the list is just a
	// // way of returning them
	// if (Collection.class.isAssignableFrom(fieldType)) {
	// Class<?> genericClass = getGeneric(field);
	// List<Object> values = new ArrayList<Object>();
	// values.add(testValue(genericClass, field));
	// values.add(testValue(genericClass, field));
	// return values;
	// }
	//
	// return testValue(fieldType, field);
	//
	// }
	//
	// private Object testValue(Class<?> fieldType, Field field) throws
	// InstantiationException, IllegalAccessException {
	// if ((fieldType == Integer.class) || (fieldType == int.class)) {
	// return new Integer(3);
	// }
	// if ((fieldType == Boolean.class) || (fieldType == boolean.class)) {
	// return new Boolean(true);
	// }
	// if (fieldType == String.class) {
	// return new String("xxX");
	// }
	// if (fieldType == ResourceGroup.class) {
	// ResourceGroup rg = new ResourceGroup();
	// rg.setConnection(connection);
	// return rg;
	// }
	// if (fieldType == Date.class) {
	// Calendar cal = new GregorianCalendar();
	// cal.setTimeInMillis(0);
	// cal.set(2010, 02, 04);
	// return cal.getTime();
	// }
	//
	// if ((fieldType == Resource.class)) {
	// Resource r = new IndividualResource(connection);
	// // necessary to save nested reference
	// r.setConnection(connection);
	// return r;
	// }
	//
	// if (fieldType == Task.class) {
	// BaseTask t = new BaseTask(connection);
	// t.setConnection(connection);
	// return t;
	// }
	//
	// if (AbstractDomainObject.class.isAssignableFrom(fieldType)) {
	// logger.debug("creating instance of " + fieldType.toString() +
	// "for field: " + field.getName());
	// AbstractDomainObject obj = (AbstractDomainObject)
	// fieldType.newInstance();
	// obj.setConnection(connection);
	// return obj;
	// }
	//
	// System.out.println("field type not defined: " + fieldType.getName());
	// return null;
	// }
	//
	// private Class<?> getGeneric(Field field) {
	// String s = field.getGenericType().toString();
	// int a = s.indexOf("<");
	// int b = s.indexOf(">");
	// if (a < 0) {
	// return null;
	// }
	// String sub = s.substring(a + 1, b);
	// try {
	// return Class.forName(sub);
	// } catch (ClassNotFoundException e) {
	// logger.error(field.getType());
	// e.printStackTrace();
	// }
	// return null;
	// }
}
